

package ru.samgtu.wst.ui.swing;

import javax.swing.SwingUtilities;
import javax.swing.tree.TreePath;

import ru.samgtu.wst.model.HttpUrl;
import ru.samgtu.wst.model.UrlEvent;
import ru.samgtu.wst.model.UrlListener;
import ru.samgtu.wst.model.UrlModel;
import ru.samgtu.wst.util.swing.AbstractTreeModel;

import java.util.logging.Logger;


public class UrlTreeModelAdapter extends AbstractTreeModel {

	protected UrlModel _model;
	private Listener _listener = new Listener();

	protected Logger _logger = Logger.getLogger(getClass().getName());

	private Object _root = new String("RooT");

	public UrlTreeModelAdapter(UrlModel model) {
		_model = model;
		_model.addUrlListener(_listener);
	}

	public Object getRoot() {
		return _root;
	}

	public Object getChild(Object parent, int index) {
		if (_model == null) {
			throw new NullPointerException(
					"Getting a child when the model is null!");
		}
		if (parent == getRoot()) {
			parent = null;
		}
		return _model.getChildAt((HttpUrl) parent, index);
	}

	public int getChildCount(Object parent) {
		if (_model == null) {
			return 0;
		}
		if (parent == getRoot()) {
			parent = null;
		}
		return _model.getChildCount((HttpUrl) parent);
	}

	public boolean isLeaf(Object node) {
		if (node == getRoot()) {
			return false;
		}
		HttpUrl url = (HttpUrl) node;
		if (url.getParameters() != null) {
			return true;
		}
		if (url.getPath().endsWith("/")) {
			return false;
		}
		return getChildCount(url) == 0;
	}

	public void valueForPathChanged(TreePath path, Object newValue) {
		// we do not support editing
	}

	protected TreePath urlTreePath(HttpUrl url) {
		Object root = getRoot();
		if ((url == null) || (url == root)) {
			return new TreePath(root);
		} else {
			Object[] urlPath = url.getUrlHierarchy();
			Object[] path = new Object[urlPath.length + 1];
			path[0] = root;
			System.arraycopy(urlPath, 0, path, 1, urlPath.length);
			return new TreePath(path);
		}
	}

	private class Listener implements UrlListener {

		public void urlAdded(final UrlEvent evt) {
			if (SwingUtilities.isEventDispatchThread()) {
				HttpUrl url = evt.getUrl();
				HttpUrl parent = url.getParentUrl();
				int index = getIndexOfChild(parent, url);
				fireChildAdded(urlTreePath(parent), index, url);
			} else {
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run() {
							urlAdded(evt);
						}
					});
				} catch (Exception e) {
					_logger.warning("Exception processing " + evt + " " + e);
					e.getCause().printStackTrace();
				}
			}
		}

		public void urlChanged(final UrlEvent evt) {
			if (SwingUtilities.isEventDispatchThread()) {
				HttpUrl url = evt.getUrl();
				HttpUrl parent = url.getParentUrl();
				int index = getIndexOfChild(parent, url);
				fireChildChanged(urlTreePath(parent), index, url);
			} else {
				if (true) {
					return;
				}
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run() {
							urlChanged(evt);
						}
					});
				} catch (Exception e) {
					_logger.warning("Exception processing " + evt + " " + e);
					e.getCause().printStackTrace();
				}
			}
		}

		public void urlRemoved(final UrlEvent evt) {
			if (SwingUtilities.isEventDispatchThread()) {
				HttpUrl url = evt.getUrl();
				HttpUrl parent = url.getParentUrl();
				int pos = 0;
				int count = getChildCount(parent);
				for (int i = 0; i < count; i++) {
					HttpUrl sibling = (HttpUrl) getChild(parent, i);
					if (url.compareTo(sibling) < 0) {
						break;
					} else {
						pos++;
					}
				}
				fireChildRemoved(urlTreePath(parent), pos, url);
			} else {
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run() {
							urlRemoved(evt);
						}
					});
				} catch (Exception e) {
					_logger.warning("Exception processing " + evt + " " + e);
					e.getCause().printStackTrace();
				}
			}
		}

		public void urlsChanged() {
			if (SwingUtilities.isEventDispatchThread()) {
				fireStructureChanged();
			} else {
				try {
					SwingUtilities.invokeAndWait(new Runnable() {
						public void run() {
							urlsChanged();
						}
					});
				} catch (Exception e) {
					_logger.warning("Exception processing event: " + e);
					e.getCause().printStackTrace();
				}
			}
		}

	}
}
